package org.lalib.entity.object.variable;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

import org.hibernate.HibernateException;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.DateType;
import org.hibernate.type.StringType;
import org.hibernate.usertype.UserType;
import org.lalib.entity.object.variable.value.DropDownVariableBean;
import org.lalib.entity.object.variable.value.ListVariableBean;

public class ValueMapperUserType implements UserType {

	@Override
	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}

	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if (x == y) {
			return true;
		} else if (x == null || y == null) {
			return false;
		} else {
			return x.equals(y);
		}
	}

	@Override
	public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {

		String prefix = resultSet.getString(names[0]);

		if (prefix != null) {

			String stringCore = resultSet.getString(names[1]);
			BigDecimal bigDecimalCore = resultSet.getBigDecimal(names[2]);
			Date dateCore = resultSet.getDate(names[3]);

			if (prefix.equals("B"))
				return bigDecimalCore;
			else if (prefix.equals("S"))
				return stringCore;
			else if (prefix.equals("D"))
				return dateCore;
			else if (prefix.equals("E"))
				return stringCore;
			else if (prefix.equals("L")) {
				ListVariableBean listVariableBean = new ListVariableBean();
				listVariableBean.getValueFromJson(stringCore);
				return listVariableBean;
			} else if (prefix.equals("DL")) {
				DropDownVariableBean downVariableBean = new DropDownVariableBean();
				downVariableBean.getValueFromJson(stringCore);
				return downVariableBean;
			}
		}

		return null;
	}

	@Override
	public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException {
		String prefix = null;
		String stringCore = null;
		BigDecimal bigDecimalCore = null;
		Date dateCore = null;

		if (value instanceof Enum) {
			stringCore = (String) value;
			prefix = "E";
		} else if (value instanceof String) {
			prefix = "S";
			stringCore = (String) value;
		} else if (value instanceof BigDecimal) {
			prefix = "B";
			bigDecimalCore = (BigDecimal) value;
		} else if (value instanceof Date) {
			prefix = "D";
			dateCore = (Date) value;
		} else if (value instanceof ListVariableBean) {
			prefix = "L";
			ListVariableBean listVariableBean = (ListVariableBean) value;
			stringCore = listVariableBean.getValueAsString();
		} else if (value instanceof DropDownVariableBean) {
			prefix = "DL";
			DropDownVariableBean downVariableBean = (DropDownVariableBean) value;
			stringCore = downVariableBean.getValueAsString();
		}

		statement.setString(index, prefix);
		statement.setString(index + 1, stringCore);
		statement.setBigDecimal(index + 2, bigDecimalCore);
		if (dateCore == null)
			statement.setDate(index + 3, null);
		else
			statement.setDate(index + 3, new java.sql.Date(dateCore.getTime()));
	}

	@Override
	public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {
		return arg0;
	}

	@Override
	@SuppressWarnings("rawtypes")
	public Class returnedClass() {
		return Object.class;
	}

	@Override
	public int[] sqlTypes() {
		return new int[] { StringType.INSTANCE.sqlType(), StringType.INSTANCE.sqlType(), BigDecimalType.INSTANCE.sqlType(),
				DateType.INSTANCE.sqlType() };
	}

	@Override
	public boolean isMutable() {
		return false;
	}

	@Override
	public int hashCode(Object obj) throws HibernateException {
		return obj.hashCode();
	}

	@Override
	public Serializable disassemble(Object obj) throws HibernateException {
		return (Serializable) obj;
	}

	@Override
	public Object assemble(Serializable arg0, Object arg1) throws HibernateException {
		return arg0;
	}
}